﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace SlamCms.SharePoint.Migration
{
	public class MigratableSite : IMigratable
	{	
		#region Properties

		public MigratableContentTypeList ContentTypes { get; set; }
		public List<MigratableFeature> Features { get; set; }
		public MigratableFieldList Fields { get; set; }
		public List<MigratableList> Lists { get; set; }
		public List<MigratableQuickLaunchItem> QuickLaunchItems { get; set; }
		public Dictionary<string, object> Properties { get; set; }
		public List<MigratableSite> Sites { get; set; }

		public string Url { get; set; }
		public string Title { get; set; }
		public string Id { get; set; }
		public string Description { get; set; }
		public string Template { get; set; }
		public uint Language { get; set; }
		public bool UseUniquePermissions { get; set; }
		public bool UseSharedNavigation { get; set; }
		public bool LinkInTopNavigationBar { get; set; }
		public MigratableSite ParentSite { get; set; }

		#endregion

		public MigratableSite()
		{	
			Lists = new List<MigratableList>();
			ContentTypes = new MigratableContentTypeList();
			Fields = new MigratableFieldList();
			QuickLaunchItems = new List<MigratableQuickLaunchItem>();
			Properties = new Dictionary<string, object>();
			Sites = new List<MigratableSite>();
			Features = new List<MigratableFeature>();
		}

		public MigratableSite(MigratableSite parentSite) :
			this()
		{
			ParentSite = parentSite;
		}

		public MigratableSite GetListSite(Guid listId)
		{
			MigratableSite foundSite = GetParentListSite(listId);

			if (foundSite == null)
				foundSite = GetListSubSite(listId);

			return foundSite;
		}

		public MigratableSite GetSite(string url)
		{
			MigratableSite foundSite = GetParentSite(url);

			if (foundSite == null)
				foundSite = GetSubSite(url);

			return foundSite;
		}

		public MigratableList GetList(Guid id)
		{
			MigratableList foundList = GetParentSiteList(id);

			if (foundList == null)
				foundList = GetSubSiteList(id);

			return foundList;
		}

		private MigratableSite GetListSubSite(Guid listId)
		{
			MigratableSite foundSite = null;
			foreach (var list in Lists)
			{
				if (list.Id.Equals(listId.ToString()))
				{
					foundSite = this;
				}
			}

			if (foundSite == null && Sites.Count > 0)
			{
				foreach (var site in Sites)
				{
					foundSite = GetListSubSite(listId);
					if (foundSite != null)
						break;
				}
			}
			return foundSite;
		}

		private MigratableSite GetSubSite(string url)
		{
			MigratableSite foundSite = null;
			if (Url.Equals(url, StringComparison.OrdinalIgnoreCase))
			{
				foundSite = this;
			}
			else if (Sites.Count > 0)
			{
				foreach (var site in Sites)
				{
					foundSite = GetSubSite(url);
					if (foundSite != null)
						break;
				}
			}
			return foundSite;
		}

		private MigratableList GetSubSiteList(Guid id)
		{
			MigratableList foundList = null;

			foreach (var list in Lists)
			{
				if (list.Id.Equals(id.ToString()))
				{
					foundList = list;
				}
			}

			if (foundList == null && Sites.Count > 0)
			{
				foreach (var site in Sites)
				{
					foundList = GetSubSiteList(id);
					if (foundList != null)
						break;
				}
			}
			return foundList;
		}

		private MigratableSite GetParentListSite(Guid listId)
		{
			MigratableSite foundSite = null;
			foreach (var list in Lists)
			{
				if (list.Id.Equals(listId.ToString()))
				{
					foundSite = this;
				}
			}

			if (foundSite == null && ParentSite != null)
			{
				foundSite = ParentSite.GetParentListSite(listId);
			}
			return foundSite;
		}

		private MigratableSite GetParentSite(string url)
		{
			MigratableSite foundSite = null;
			if (Url.Equals(url, StringComparison.OrdinalIgnoreCase))
			{
				foundSite = this;
			}
			else if (ParentSite != null)
			{
				foundSite = ParentSite.GetParentSite(url);
			}
			return foundSite;
		}

		private MigratableList GetParentSiteList(Guid id)
		{
			MigratableList foundList = null;
			foreach (var list in Lists)
			{
				if (list.Id.Equals(id.ToString()))
				{
					foundList = list;
				}
			}

			if (foundList == null && ParentSite != null)
			{
				foundList = ParentSite.GetParentSiteList(id);
			}
			return foundList;
		}
		
		#region Serialization

		public XElement ToXml()
		{
			XElement node = new XElement("Site");
			node.Add(new XAttribute("Id", Id));
			node.Add(new XAttribute("Title", Title));
			node.Add(new XAttribute("Description", Description));
			node.Add(new XAttribute("Url", Url));
			node.Add(new XAttribute("Template", Template));
			node.Add(new XAttribute("Language", Language));
			node.Add(new XAttribute("UseUniquePermissions", UseUniquePermissions));
			node.Add(new XAttribute("UseSharedNavigation", UseSharedNavigation));
			node.Add(new XAttribute("LinkInTopNavigationBar", LinkInTopNavigationBar));
			node.Add(FeaturesToXml());
			node.Add(PropertiesToXml());
			node.Add(Fields.ToXml());
			node.Add(ContentTypes.ToXml());
			node.Add(ListsToXml());
			node.Add(QuickLaunchToXml());
			node.Add(SitesToXml());

			return node;
		}

		public void FromXml(XElement element)
		{
			this.Id = element.Attribute("Id").Value;
			this.Title = element.Attribute("Title").Value;
			this.Description = element.Attribute("Description").Value;
			this.Url = element.Attribute("Url").Value;
			this.Template = element.Attribute("Template").Value;
			this.Language = uint.Parse(element.Attribute("Language").Value);
			this.UseUniquePermissions = bool.Parse(element.Attribute("UseUniquePermissions").Value);
			this.UseSharedNavigation = bool.Parse(element.Attribute("UseSharedNavigation").Value);
			this.LinkInTopNavigationBar = bool.Parse(element.Attribute("LinkInTopNavigationBar").Value);
			this.ContentTypes.FromXml(element);
			this.Fields.FromXml(element);
			FeaturesFromXml(element);
			ListsFromXml(element);
			PropertiesFromXml(element);
			SitesFromXml(element);

			foreach (XElement quickLaunchElement in element.Element("QuickLaunch").Elements())
			{
				MigratableQuickLaunchItem quickLaunchItem = new MigratableQuickLaunchItem();
				quickLaunchItem.FromXml(quickLaunchElement);
				QuickLaunchItems.Add(quickLaunchItem);
			}
		}

		private XElement FeaturesToXml()
		{
			XElement node = new XElement("Features");
			foreach (MigratableFeature feature in Features)
			{
				node.Add(feature.ToXml());
			}
			return node;
		}

		private void FeaturesFromXml(XElement element)
		{
			XElement featuresElement = element.Element("Features");
			if (featuresElement != null && featuresElement.HasElements)
			{
				foreach (XElement featureElement in featuresElement.Elements())
				{
					MigratableFeature feature = new MigratableFeature();
					feature.FromXml(featureElement);
					Features.Add(feature);
				}
			}
		}

		private XElement ListsToXml()
		{
			XElement element = new XElement("Lists");
			foreach (MigratableList list in Lists)
			{
				element.Add(list.ToXml());
			}
			return element;
		}

		private void ListsFromXml(XElement element)
		{
			XElement listsElement = element.Element("Lists");
			if (listsElement != null && listsElement.HasElements)
			{
				foreach (XElement listElement in listsElement.Elements())
				{
					MigratableList list = new MigratableList();
					list.FromXml(listElement);
					this.Lists.Add(list);
				}
			}
		}

		private XElement PropertiesToXml()
		{
			XElement node = new XElement("Properties");
			foreach (KeyValuePair<string, object> property in Properties)
			{
				node.Add(new XElement("Property", new XAttribute("Name", property.Key), new XAttribute("Value", property.Value ?? "")));
			}
			return node;
		}

		private void PropertiesFromXml(XElement element)
		{
			XElement propertiesElement = element.Element("Properties");
			if (propertiesElement != null && propertiesElement.HasElements)
			{
				foreach (XElement propertyElement in propertiesElement.Elements())
				{
					this.Properties.Add(propertyElement.Attribute("Name").Value, propertyElement.Attribute("Value").Value);
				}
			}
		}

		private XElement QuickLaunchToXml()
		{
			XElement quickLaunchNode = new XElement("QuickLaunch");
			foreach (var quickLaunchItem in QuickLaunchItems)
			{
				quickLaunchNode.Add(quickLaunchItem.ToXml());
			}
			return quickLaunchNode;
		}

		private XElement SitesToXml()
		{
			XElement element = new XElement("Sites");
			foreach (var site in Sites)
			{
				element.Add(site.ToXml());
			}
			return element;
		}

		private void SitesFromXml(XElement element)
		{
			XElement sitesElement = element.Element("Sites");
			if (sitesElement != null && sitesElement.HasElements)
			{
				foreach (XElement siteElement in sitesElement.Elements())
				{
					MigratableSite site = new MigratableSite();
					site.FromXml(siteElement);
					site.ParentSite = this;
					Sites.Add(site);
				}
			}
		}

		#endregion
	}
}
